﻿using System;
using System.Collections.Generic;
using System.Text;

namespace T3K.SketchEditor.AvrBuilder {
    public class ArgsParser {

        private string _command;
        private string _description;
        private string _error = null;
        private Dictionary<string, Argument> _arguments;
        private const char StartArg = '-';

        public bool AsError {
            get { return (_error == null || _error.Trim() == string.Empty); }
        }

        public string Error {
            get { return _error; }
        }

        public string Command {
            get { return _command; }
            set { _command = value; }
        }

        public string Description {
            get { return _description; }
            set { _description = value; }
        }

        public ArgsParser(string command) {
            this._command = command;
            this._description = null;
            this._arguments = new Dictionary<string, Argument>();
        }

        public Argument this[string argument] {
            get {
                if (_arguments.ContainsKey(argument))
                    return _arguments[argument];
                else
                    return null;
            }
            set {
                if (!_arguments.ContainsKey(argument))
                    _arguments.Add(argument, value);
                else
                    _arguments[argument] = value;
            }
        }

        public bool Parse(string[] args) {
            string[] tokensA = string.Join(" ", args).Split('"');
            List<string> args2 = new List<string>();
            for (int i = 0; i < tokensA.Length; i++) {
                if ((i % 2) != 0)
                    args2.Add(tokensA[i]);
                else {
                    args2.AddRange(tokensA[i].Split(new char[] {' ', '\t'}, StringSplitOptions.RemoveEmptyEntries));
                }
            }

            for (int i = 0; i < args2.Count; i++) {
                if (args2[i][0] == StartArg) {
                    string arg = args2[i].Substring(1);
                    if (_arguments.ContainsKey(arg)) {
                        if (_arguments[arg].Type == ArgumentType.Argument) {
                            i++; //goto value;
                            if (i < args2.Count && !(args2[i][0] == StartArg)) {
                                _arguments[arg].Value.Add(args2[i]);
                            } else {
                                _error = string.Format("{0}: argument -{1} expects a parameter which as not supplied",
                                    _command, arg);
                                return false;
                            }
                        }
                        _arguments[arg].Match = true;
                    }
                }
            }

            foreach (Argument a in _arguments.Values) {
                if (a.Required && !a.Match) {
                    _error = string.Format("{0}: expects -{1} argument/switch which as not supplied",
                        _command, a.Name);
                    return false;
                }
            }

            return true;
        }

        public string Usage() {
            StringBuilder sBuilder = new StringBuilder();
            sBuilder.AppendLine(_description);
            sBuilder.AppendLine("Usage:");
            sBuilder.AppendFormat("{0} ", _command);
            foreach (Argument a in _arguments.Values) {
                string argDef = string.Format("-{0}{1}", a.Name, (a.Type == ArgumentType.Switch) ? "" : " " + a.Parameter);
                if (!a.Required) {
                    argDef = string.Format("[{0}]", argDef);
                }
                sBuilder.AppendFormat("{0} ", argDef);
            }

            sBuilder.AppendLine();
            sBuilder.AppendLine();

            foreach (Argument a in _arguments.Values) {
                sBuilder.AppendFormat(" -{0}\t{1}\n", a.Name, a.Description);
            }

            return sBuilder.ToString();
        }

        public enum ArgumentType {
            Switch, Argument
        }

        public class Argument {
            private string _name;
            private string _paramName;
            private string _description;
            private ArgumentType _type;
            private List<string> _value;
            private bool _required;
            private bool _match;

            public string Name {
                get { return _name; }
                set { _name = value; }
            }

            public string Parameter {
                get { return _paramName; }
                set { _paramName = value; }
            }

            public string Description {
                get { return _description; }
                set {

                    if (!_required)
                        _description = string.Format("(Optional) {0}", value);
                    else
                        _description = value; 
                }
            }

            public ArgumentType Type {
                get { return _type; }
                set { _type = value; }
            }

            public List<string> Value {
                get { return _value; }
                set { _value = value; }
            }

            public bool Required {
                get { return _required; }
                set { _required = value; }
            }

            public bool Match {
                get { return _match; }
                set { _match = value; }
            }

            public Argument(string name, ArgumentType type, bool required) {
                _name = name;
                _type = type;
                _required = required;
                _value = new List<string>();
                _match = false;
                _paramName = "param";
                _description = "no description";
            }

        }

    }
}
